// JSON Web Token
const jwt = require('jsonwebtoken');
const { expressjwt } = require('express-jwt');
const {
  PrivateKey,
  PublicKey,
  Access_Expired_Time,
  Refresh_Expired_Time,
  whiteRouteList,
} = require('../config/index');

class TokenManager {
  constructor({ private_key, public_key, access_expired_time, refresh_expired_time }, options) {
    this.secretOrPrivateKey = private_key;
    this.secretOrPublicKey = public_key;
    this.access_expired_time = access_expired_time;
    this.refresh_expired_time = refresh_expired_time;

    //algorithm + keyid + noTimestamp + expiresIn + notBefore
    this.options = options;
  }

  // 签发token
  sign(payload, signOptions) {
    const jwtSignOptions = { ...this.options, ...signOptions };
    return jwt.sign(payload, this.secretOrPrivateKey, jwtSignOptions);
  }

  // 校验token
  verify(payload, verifyOptions) {
    const jwtVerifyOptions = { ...this.options, ...verifyOptions };
    return jwt.verify(payload, this.secretOrPrivateKey, jwtVerifyOptions);
  }

  // 签发access_token
  create_access_token(payload, signOptions) {
    return this.sign(payload, {
      expiresIn: this.access_expired_time,
      ...signOptions,
    });
  }

  // 签发refresh_token
  create_refresh_token(payload, signOptions) {
    return this.sign(payload, {
      expiresIn: this.refresh_expired_time,
      ...signOptions,
    });
  }

  /**
   * token守卫，每一个路由都校验，白名单中路由无需校验。
   *  接收的请求头token格式为: "authorization"|"Authorization" : `Bearer ${token}`  格式
   */
  guard(path = whiteRouteList, isRevoked) {
    return expressjwt({
      secret: this.secretOrPublicKey,
      algorithms: ['HS256'],
      isRevoked, // 自定义函数，判断token是否失效

      // credentialsRequired: true, // 默认true; 如果为 false，则在请求不包含令牌时继续下一个中间件，而不是失败

      getToken: (req) => {
        if (req?.headers?.refresh_token) {
          return req.headers.refresh_token.replace(/^Bearer /, '');
        }
        if (req?.headers?.authorization) {
          return req.headers.authorization.replace(/^Bearer /, '');
        }
      }, // 自定义令牌位置 可选, 默认 req.headers.authorization

      // onExpired(req, err) {
      //   if (new Date() - err.inner.expiredAt < 5000) return;
      //   throw err;
      // }, // 处理过期token的函数
    }).unless({ path, pathMatch: new RegExp('/api/admin/article/\\d+') });
  }
}

let token_manager = new TokenManager({
  private_key: PrivateKey,
  public_key: PublicKey,
  access_expired_time: Access_Expired_Time,
  refresh_expired_time: Refresh_Expired_Time,
});

module.exports = token_manager;
